
#include "Core.h"
#include "BiCE.h"
#include "ShadowDB.h"

#include <stdio.h>
#include <stdlib.h>

#include <set>
#include <algorithm>
#include <string>
#include <iostream>
#include <fstream>
#include <sstream>
using namespace std;

void ShadowDB::add(const Sketch &s, const Record &r)
{
	db[s].push_back(r);
}
void ShadowDB::save(const char* filename)
{
	ofstream fout(filename);
	if(!fout.good()) {
		printf("can't open file %s to write\n",filename);
		exit(1);
	}
	
	map< Sketch, vector<Record> >::iterator it;
	for(it = db.begin(); it!= db.end(); it++) {
		Sketch s = it->first;
		vector<Record> rs = it->second;
		if(rs.size()==0)
			continue;
		vector<Record>::iterator it2;
		fout << s << rs.size() << "\t";
		for(it2=rs.begin();it2!=rs.end();it2++)
			fout << *it2;
		fout << endl;
	}
	fout.close();
}

void ShadowDB::load(const char* filename)
{
	ifstream fin(filename);

	if(!fin.good()) {
		printf("can't open file %s to read\n",filename);
		exit(1);
	}

	string line;
	int i;
	while(1) {
		getline(fin,line);
		if(fin.eof())
			break;

		stringstream sin(line);
		Sketch s;
		int N;
		Record r;
		sin >> s >> N;
		for(i=0;i<N;i++) {
			sin >> r;
			add(s,r);
		}
	}
}

inline bool within(Position p, Position pe)
{
	return abs(p.x-pe.x) <= NEARBY && abs(p.y-pe.y) <= NEARBY;
}

inline bool mycompare( pair<Record,int> a, pair<Record,int> b)
{
	return a.second > b.second;
}
const vector<Record>& ShadowDB::query(int height,int width,unsigned char *data)
{
	// init
	query_buf.clear();

	// count vote time of each patch in db
	map< Record, int> has_vote;
	// record is fid and offset
	map< Record, int> cand;

	BiCE b(height,width,data);
	//cout << b << endl;
	
	const vector< pair<Position,Sketch> > & ps = b.postion_sketch_pairs;
	int i,j;
	
	for(i=0; i<ps.size() ;i++) {
		Position p = ps[i].first;
		Sketch s = ps[i].second;
		const vector<Record> & rs = db[s];
		for(j=0; j < rs.size() ; j++) {
			Position pe = rs[j].position;
			if( !within(p,pe) || has_vote[ rs[j] ] > 4 )	// only consider nearby grid and each descriptor limit 4 vote
				continue;
			cand[ Record( Position( p.y-pe.y , p.x-pe.x ) ,rs[j].fileID ) ]++;
			has_vote[ rs[j] ]++;
		}
	}
	
	map< Record, int>::iterator it;
	vector< pair<Record,int> > sort_vote;
	for(it = cand.begin(); it != cand.end();it++)
		sort_vote.push_back( make_pair(it->first,it->second) );

	sort(sort_vote.begin(),sort_vote.end(),mycompare);
	
	set<int> fid;
	for(i=0;i<CANDIDATE && i < sort_vote.size();i++) {
		//if( sort_vote[i].first.fileID == 2 ) 
		//	cout << sort_vote[i].first << " " << sort_vote[i].second << endl;
		if(fid.count(sort_vote[i].first.fileID))
			continue;
		if( sort_vote[i].second == 0)
			break;
		query_buf.push_back(sort_vote[i].first);
		fid.insert(sort_vote[i].first.fileID);
	}
	return query_buf;
}
